# !/usr/bin/python3
# -*- coding:utf-8 -*-
"""
@author: JHC000abc@gmail.com
@file: util_bos.py
@time: 2025/4/2 15:52 
@desc: 

"""

import time

import requests
from baidubce.bce_client_configuration import BceClientConfiguration
from baidubce.auth.bce_credentials import BceCredentials
from baidubce.services.bos.bos_client import BosClient

from baidubce import utils
from baidubce.services.bos import storage_class
from urllib import parse
import hashlib


class URLParser(object):
    """
    URL 解析相关类
    """

    def __init__(self, url):
        """

        :param url:
        """
        self.url = url
        if len(self.url.split("?")) == 2:
            url_tail, self.desc = self.url.split("?")
        else:
            url_tail, self.desc = self.url, ""
        url_split_double = url_tail.split("://")
        url_split_single = url_split_double[1].split("/")
        self.protocol = url_split_double[0]
        self.host = url_split_single[0]
        self.path_lis = url_split_single[1:-1]
        self.path = "/".join(self.path_lis)
        try:
            self.name, self.tail = url_split_single[-1].split(".")
        except BaseException:
            self.name = ".".join(url_split_single[-1].split(".")[:-1])
            self.tail = url_split_single[-1].split(".")[-1]
        self.name = parse.unquote(self.name)

    def __str__(self):
        """
        print() 自动调用
        :return:
        """
        return f"URL: {self.url}\nPROTOCOL: {self.protocol}\n" \
               f"HOST: {self.host}\nPATH: {self.path}\n" \
               f"PATH_LIS: {self.path_lis}\n" \
               f"NAME: {self.name}\nTAIL: {self.tail}\n" \
               f"DESC: {self.desc}\n"


class Online(object):
    """

    """

    def __init__(self):
        self.slat = "sts"
        self.duration_seconds = 129600
        self.bos_client = None
        self.host_list = ['bd.bcebos.com', 'bj.bcebos.com', 'hkg.bcebos.com']

    def stand_format_url(self, url):
        """

        :param url:
        :return:
        """
        url_obj = URLParser(url)
        if url_obj.host in self.host_list:
            return url
        else:
            host_split = url_obj.host.split(".")
            bucket = host_split[0]
            host = ".".join(host_split[1:])
            url = f"{url_obj.protocol}://{host}/{bucket}/{url_obj.path}/{url_obj.name}.{url_obj.tail}"
            return url

    def GetBucketKey(self, url):
        """

        :param url:
        :return:
        """
        tmp_list = url.split('/')
        # 适配历史上由众测接口生成的下载文件
        if 'json-api/v1' in url:
            bucket = tmp_list[5]
            key = '/'.join(tmp_list[6:])
        elif tmp_list[2] in ['bd.bcebos.com', 'bj.bcebos.com', 'hkg.bcebos.com']:
            bucket = tmp_list[3]
            key = '/'.join(tmp_list[4:])
        else:
            bucket = tmp_list[2].split('.')[0]
            key = '/'.join(tmp_list[3:])
        return bucket, key

    def _download(self, bos_client, file, bucket_name, key):
        """
        自带重试的下载
        :param bos_client:
        :param file:
        :param bucket_name:
        :param key:
        :param retry:
        :return:
        """
        bos_client.get_object_to_file(
            bucket_name, key, file, progress_callback=utils.default_progress_callback)
        return file

    def _upload(self, bos_client, file, bucket_name, key, status):
        """
        自带重试的上传
        :param bos_client:
        :param file:
        :param bucket_name:
        :param key:
        :param status:
        :param retry:
        :return:
        """
        if status == 0:
            bos_client.put_object_from_file(
                bucket_name,
                key,
                file,
                storage_class=storage_class.STANDARD,
                progress_callback=utils.default_progress_callback
            )
        else:
            bos_client.put_super_obejct_from_file(
                bucket_name,
                key,
                file,
                chunk_size=5,
                storage_class=storage_class.STANDARD,
                progress_callback=utils.default_progress_callback
            )
        return file


class BosOnline(Online):
    """
    正式
    """

    def __init__(self):
        super().__init__()

    def init_bos_client(self, url):
        """

        :return:
        """
        if not self.bos_client:
            data = self.get_temp_token(url)
            if data:
                config = BceClientConfiguration(
                    credentials=BceCredentials(data["access_key_id"], data["secret_access_key"]),
                    endpoint=data["host"], security_token=data['session_token'])
                self.bos_client = BosClient(config)
        return self.bos_client

    def make_md5(self, data, salt: bytes = b""):
        """

        :param data:
        :param salt:
        :return:
        """
        md5_machine = hashlib.md5(salt)
        md5_machine.update(data.strip().encode('utf-8'))
        return md5_machine.hexdigest()

    def get_temp_token(self, url):
        """

        :return:
        """
        result = {}
        bucket_name, key = self.GetBucketKey(url)
        folder = key.split("/")[0]
        host = url.split(bucket_name)[0][0:-1]
        params = {
            'timestamp': int(time.time()),
            'sign': '',
            'source': 1,
            'ct_user_id': 19999,
            'bucket': bucket_name,
            'permission': 'WRITE,READ',
            'region': 'bj',
            'object': f'{folder}/*',
            'duration_seconds': self.duration_seconds,
        }
        tmp = ['{}={}'.format(key, params[key]) for key in sorted(params) if key != 'sign']
        tmp.append(f'key={self.slat}')
        params['sign'] = self.make_md5(data='&'.join(tmp))
        url = 'https://test.baidu.com/collection/api/getBosStsCredential'
        response = requests.post(url, data=params)
        response.encoding = "utf-8"
        data = response.json()
        result = data["result"]
        result["host"] = host

        return result

    def upload(self, url, file, status=0, tran_url=False):
        """
        上传
        :param url:
        :param file:
        :param status:
        :param tran_url:
        :return:
        """
        if tran_url:
            url = self.stand_format_url(url)
        bucket_name, key = self.GetBucketKey(url)
        self.init_bos_client(url)
        return self._upload(self.bos_client, file, bucket_name, key, status)

    def download(self, url, file, tran_url=False):
        """
        下载
        :param url:
        :param file:
        :param tran_url:
        :return:
        """
        if tran_url:
            url = self.stand_format_url(url)
        bucket_name, key = self.GetBucketKey(url)
        self.init_bos_client(url)
        return self._download(self.bos_client, file, bucket_name, key)

    def get_download_url(self, url, tran_url=False):
        """

        :param url:
        :param tran_url:
        :return:
        """
        if tran_url:
            url = self.stand_format_url(url)
        bucket_name, key = self.GetBucketKey(url)
        self.init_bos_client(url)
        return self.bos_client.generate_pre_signed_url(
            bucket_name, key, time.time(), -1).decode("utf-8")


if __name__ == '__main__':
    bos = BosOnline()
    url = "https://bj.bcebos.com/petite-mark/public_read/vipshop/1/1/1/1/1/1/11/1.png"
    local = r"D:\Project\Python\baidu\crowdtest\collection-script\CR\tests\zzprojects\img.png"
    print(bos.upload(url, local))
